package gagak.framework.web.paramresovler.requestbody;

import gagak.framework.web.exception.HttpMediaTypeNotSupportedException;
import gagak.framework.web.exception.HttpMessageNotReadableException;
import gagak.framework.web.paramresovler.AbstractMessageConverterMethodProcessor;
import gagak.framework.web.paramresovler.converter.json.ContentNegotiationManager;
import gagak.framework.web.annonation.Nullable;
import gagak.framework.web.annonation.RequestBody;
import gagak.framework.web.param.MethodParameter;
import gagak.framework.web.support.request.NativeWebRequest;
import gagak.framework.web.utils.Assert;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.List;

/*
 * @program: ce
 * @description: 解析@RequestBody的参数
 * @author: houhong
 * @create: 2022-11-30 20:49
 */
public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {


    public RequestResponseBodyMethodProcessor(List<HttpMessageConverter<?>> converters) {
        super(converters);
    }

    public RequestResponseBodyMethodProcessor(List<HttpMessageConverter<?>> converters,
                                              @Nullable ContentNegotiationManager manager) {

        super(converters, manager);
    }

    public RequestResponseBodyMethodProcessor(List<HttpMessageConverter<?>> converters,
                                              @Nullable List<Object> requestResponseBodyAdvice) {

        super(converters, null, requestResponseBodyAdvice);
    }

    public RequestResponseBodyMethodProcessor(List<HttpMessageConverter<?>> converters,
                                              @Nullable ContentNegotiationManager manager, @Nullable List<Object> requestResponseBodyAdvice) {

        super(converters, manager, requestResponseBodyAdvice);
    }


    /*
     * 支持解析 RequestBody
     */
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(RequestBody.class);
    }


    @Override
    public Object resolveArgument(MethodParameter methodParameter, NativeWebRequest webRequest) throws Exception {
        // 所以核心逻辑：读取流、消息换换等都在父类里已经完成。子类直接调用就可以拿到转换后的值arg
        // arg 一般都是个类对象。比如Person实例
        Object arg = readWithMessageConverters(webRequest, methodParameter, methodParameter.getNestedGenericParameterType());

        return arg;
    }


    /*
     * 1:这一层负责将 httpSerlet 封装成 ServletServerHttpRequest 做一些解析后的校验
     *
     * 2: 继续的读取交给上一层
     */
    @Override
    protected <T> Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter parameter,
                                                   Type paramType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {

        HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
        Assert.state(servletRequest != null, "No HttpServletRequest");

        //封装成框架的  将 request 包装成 -->（HttpInputMessage） ServletServerHttpRequest -- 里面对http协议进行更多的解析
        ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(servletRequest);

        Object arg = readWithMessageConverters(inputMessage, parameter, paramType);
        if (arg == null && checkRequired(parameter)) {
            throw new HttpMessageNotReadableException("Required request body is missing: ");
        }
        return arg;
    }

    protected boolean checkRequired(MethodParameter parameter) {
        RequestBody requestBody = parameter.getParameterAnnotation(RequestBody.class);
        return (requestBody != null && requestBody.required());
    }
}